package com.bjsxt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjsxt.domain.SysUser;
import com.bjsxt.domain.SysUserRole;
import com.bjsxt.dto.SysUserDto;
import com.bjsxt.mapper.SysUserMapper;
import com.bjsxt.model.SysUserVo;
import com.bjsxt.service.SysUserRoleService;
import com.bjsxt.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    /**
     * 用户角色业务层接口
     */
    @Autowired
    private SysUserRoleService sysUserRoleService;

    /**
     * 根据姓名和手机号分页查询员工数据
     *
     * @param page     分页对象<SysUser>
     * @param fullname 姓名
     * @param mobile   手机号
     * @return 员工分页数据
     */
    @Override
    public Page<SysUserVo> pageByMobileAndFullname(Page<SysUser> page, String fullname, String mobile) {
        // 根据姓名或手机号模糊查询分页数据
        Page<SysUser> sysUsersPage = page(page, new LambdaQueryWrapper<SysUser>()
                .like(StringUtils.isNotBlank(fullname), SysUser::getFullname, fullname)
                .like(StringUtils.isNotBlank(mobile), SysUser::getMobile, mobile)
        );
        // page 对象泛型转换
        IPage<SysUserVo> sysUsersVoPage = sysUsersPage.convert(item -> {
            // 创建需要转换的 vo 数据对象.
            SysUserVo sysUserVo = new SysUserVo();
            // 进行值的 copy
            BeanUtil.copyProperties(item, sysUserVo);
            // 返回对象
            return sysUserVo;
        });
        // 取出分页对象的数据
        List<SysUserVo> sysUserVos = sysUsersVoPage.getRecords();
        // 如果集合不为空
        if (CollectionUtil.isNotEmpty(sysUserVos)) {
            // 循环遍历数据
            for (SysUserVo sysUserVo : sysUserVos) {
                // 根据用户 id 查询用户角色数据
                List<SysUserRole> sysUserRoles = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>()
                        .eq(SysUserRole::getUserId, sysUserVo.getId())
                );
                // 如果查询的角色数据不是空
                if (CollectionUtil.isNotEmpty(sysUserRoles)) {
                    // 进行角色字符的拼接获取
                    String roleStrings = sysUserRoles.stream()
                            .map(sysUserRole -> sysUserRole.getRoleId().toString())
                            .collect(Collectors.joining(","));
                    // 对 vo 里面的数据进行替换角色数据字符串
                    sysUserVo.setRoleStrings(roleStrings);
                }
            }
        }
        // 返回查询的 vo 分页对象
        return (Page<SysUserVo>) sysUsersVoPage;
    }

    /**
     * 添加员工
     *
     * @param sysUserDto 员工传输数据对象
     * @return 是否添加成功 true: 成功 false: 失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addUserDto(SysUserDto sysUserDto) {
        // 创建密码的加密对象
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        // 进行密码的加密 并对实体类中的密码进行替换
        sysUserDto.setPassword(bCryptPasswordEncoder.encode(sysUserDto.getPassword()));
        // 添加创建的员工对象
        SysUser sysUser = new SysUser();
        // 进行值的 copy
        BeanUtil.copyProperties(sysUserDto, sysUser);
        // 调用保存方法进行数据的保存
        boolean flag = save(sysUser);
        // 如果保存失败直接返回 false
        if (!flag) return false;
        // 将角色字符串进行值的转换
        String[] roleIds = sysUserDto.getRoleStrings().split(",");
        // 创建角色用户对象集合
        List<SysUserRole> sysUserRoleList = new ArrayList<>(roleIds.length);
        // 循环遍历
        for (String roleId : roleIds) {
            // 创建角色用户对象
            SysUserRole sysUserRole = new SysUserRole();
            // 设置相关的属性值
            sysUserRole.setRoleId(Long.valueOf(roleId));
            sysUserRole.setUserId(sysUser.getId());
            // 将值放入集合中
            sysUserRoleList.add(sysUserRole);
        }
        // 进行值的批量添加
        return sysUserRoleService.saveBatch(sysUserRoleList);
    }

    /**
     * 更新员工
     *
     * @param sysUserDto 员工传输数据对象
     * @return 是否更新成功 true: 成功 false: 失败
     */
    @Override
    public boolean updateUserDto(SysUserDto sysUserDto) {
        // 创建密码的加密对象
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        // 进行密码的加密 并对实体类中的密码进行替换
        sysUserDto.setPassword(bCryptPasswordEncoder.encode(sysUserDto.getPassword()));
        // 添加创建的员工对象
        SysUser sysUser = new SysUser();
        // 进行值的 copy
        BeanUtil.copyProperties(sysUserDto, sysUser);
        // 调用保存方法进行数据的保存
        boolean flag = updateById(sysUser);
        // 如果保存失败直接返回 false
        if (!flag) return false;
        // 将之前跟当前用户关联的中间表数据删除
        flag = sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, sysUserDto.getId()));
        // 如果删除失败直接返回 false
        if (!flag) return false;
        // 将角色字符串进行值的转换
        String[] roleIds = sysUserDto.getRoleStrings().split(",");
        // 创建角色用户对象集合
        List<SysUserRole> sysUserRoleList = new ArrayList<>(roleIds.length);
        // 循环遍历
        for (String roleId : roleIds) {
            // 创建角色用户对象
            SysUserRole sysUserRole = new SysUserRole();
            // 设置相关的属性值
            sysUserRole.setRoleId(Long.valueOf(roleId));
            sysUserRole.setUserId(sysUser.getId());
            // 将值放入集合中
            sysUserRoleList.add(sysUserRole);
        }
        // 进行值的批量添加
        return sysUserRoleService.saveBatch(sysUserRoleList);
    }

    /**
     * 删除（根据ID 批量删除）
     *
     * @param idList 主键ID列表
     * @return 是否删除成功 true: 成功 false: 失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        // 调用父方法进行数据的移除
        boolean flag = super.removeByIds(idList);
        // 如果移除失败那么直接返回失败
        if (!flag) return false;
        // 移除跟当前用户有关的中间表的数据
        return sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, idList));
    }
}
